package com.tywj.lib.core.common.extension

import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Paint
import android.graphics.drawable.Drawable
import android.net.Uri
import android.text.Spannable
import android.text.SpannableStringBuilder
import android.text.TextPaint
import android.text.style.DynamicDrawableSpan
import android.text.style.ForegroundColorSpan
import android.text.style.ImageSpan
import android.text.style.ReplacementSpan
import androidx.annotation.ColorInt
import androidx.annotation.ColorRes
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
import androidx.core.text.inSpans
import com.tywj.lib.core.common.util.AppUtil
import com.tywj.lib.core.common.util.ResourcesUtil

/**
 * <pre>
 *     author : June Yang
 *     time   : 2020/5/7
 *     desc   : SpannableStringBuilder扩展
 *     version: 1.0.0
 * </pre>
 */

inline fun SpannableStringBuilder.foregroundColor(
    @ColorInt color: Int,
    builderAction: SpannableStringBuilder.() -> Unit
) = inSpans(ForegroundColorSpan(color), builderAction = builderAction)

inline fun SpannableStringBuilder.foregroundColorRes(
    @ColorRes colorId: Int,
    builderAction: SpannableStringBuilder.() -> Unit
) = inSpans(ForegroundColorSpan(ResourcesUtil.getColor(colorId)), builderAction = builderAction)

fun SpannableStringBuilder.append(@StringRes resId: Int): SpannableStringBuilder {
    append(ResourcesUtil.getString(resId))
    return this
}

fun SpannableStringBuilder.appendVerticalCenter(
    @StringRes resId: Int,
    fontSizePx: Float
): SpannableStringBuilder {
    val start = length
    append(ResourcesUtil.getString(resId))
    setSpan(VerticalCenterSpan(fontSizePx), start, length, Spannable.SPAN_INCLUSIVE_EXCLUSIVE)
    return this
}

fun SpannableStringBuilder.appendVerticalCenter(
    text: String,
    fontSizePx: Float
): SpannableStringBuilder {
    val start = length
    append(text)
    setSpan(VerticalCenterSpan(fontSizePx), start, length, Spannable.SPAN_INCLUSIVE_EXCLUSIVE)
    return this
}


fun SpannableStringBuilder.appendImage(
    bitmap: Bitmap,
    verticalAlignment: Int = CustomImageSpan.ALIGN_CENTER
) = appendImage(
    CustomImageSpan(
        bitmap,
        verticalAlignment
    )
)

fun SpannableStringBuilder.appendImage(
    drawable: Drawable,
    verticalAlignment: Int = CustomImageSpan.ALIGN_CENTER
) = appendImage(
    CustomImageSpan(
        drawable,
        verticalAlignment
    )
)

fun SpannableStringBuilder.appendImage(
    uri: Uri,
    verticalAlignment: Int = CustomImageSpan.ALIGN_CENTER
) = appendImage(
    CustomImageSpan(
        uri,
        verticalAlignment
    )
)

fun SpannableStringBuilder.appendImage(
    @DrawableRes resId: Int,
    verticalAlignment: Int = CustomImageSpan.ALIGN_CENTER
) = appendImage(
    CustomImageSpan(
        resId,
        verticalAlignment
    )
)

fun SpannableStringBuilder.appendImage(
    span: ImageSpan
): SpannableStringBuilder {
    val start = length
    append("<img>")
    setSpan(span, start, length, Spannable.SPAN_INCLUSIVE_EXCLUSIVE)
    return this
}

/**
 * 增加图片垂直居中
 */
class CustomImageSpan : ImageSpan {

    constructor(bitmap: Bitmap, verticalAlignment: Int = ALIGN_CENTER) : super(
        AppUtil.context, bitmap, verticalAlignment)

    constructor(drawable: Drawable, verticalAlignment: Int = ALIGN_CENTER) : super(drawable, verticalAlignment)

    constructor(uri: Uri, verticalAlignment: Int = ALIGN_CENTER) : super(
        AppUtil.context, uri, verticalAlignment)

    constructor(@DrawableRes resId: Int, verticalAlignment: Int) : super(AppUtil.context, resId, verticalAlignment)

    companion object {
        // 居中对齐
        const val ALIGN_CENTER = Int.MAX_VALUE - 1
    }

    override fun getSize(paint: Paint, text: CharSequence, start: Int, end: Int,
                         fontMetricsInt: Paint.FontMetricsInt?): Int {
        return if (mVerticalAlignment == ALIGN_CENTER) {
            val drawable = drawable
            val rect = drawable.bounds
            if (fontMetricsInt != null) {
                val fmPaint = paint.fontMetricsInt
                val fontHeight = fmPaint.descent - fmPaint.ascent
                val drHeight = rect.bottom - rect.top
                val centerY = fmPaint.ascent + fontHeight / 2

                fontMetricsInt.ascent = centerY - drHeight / 2
                fontMetricsInt.top = fontMetricsInt.ascent
                fontMetricsInt.bottom = centerY + drHeight / 2
                fontMetricsInt.descent = fontMetricsInt.bottom
            }
            rect.right
        } else {
            super.getSize(paint, text, start, end, fontMetricsInt)
        }
    }

    override fun draw(canvas: Canvas, text: CharSequence, start: Int, end: Int, x: Float, top: Int, y: Int, bottom: Int, paint: Paint) {
        val b = drawable
        canvas.save()

        var transY = bottom - b.bounds.bottom
        when (mVerticalAlignment) {
            DynamicDrawableSpan.ALIGN_BASELINE -> transY -= paint.fontMetricsInt.descent
            ALIGN_CENTER -> {
                val fmPaint = paint.fontMetricsInt
                val fontHeight = fmPaint.descent - fmPaint.ascent
                val centerY = y + fmPaint.descent - fontHeight / 2
                transY = centerY - (drawable.bounds.bottom - drawable.bounds.top) / 2
            }
        }

        canvas.translate(x, transY.toFloat())
        b.draw(canvas)
        canvas.restore()
    }
}

/**
 * 文本垂直居中
 */
class VerticalCenterSpan(private val fontSizePx: Float) : ReplacementSpan() {

    override fun getSize(paint: Paint, text: CharSequence, start: Int, end: Int, fm: Paint.FontMetricsInt?): Int {
        var temp = text
        temp = temp.subSequence(start, end)
        val p = getCustomTextPaint(paint)
        return p.measureText(temp.toString()).toInt()
    }

    override fun draw(canvas: Canvas, text: CharSequence, start: Int, end: Int, x: Float, top: Int, y: Int, bottom: Int, paint: Paint) {
        var temp = text
        temp = temp.subSequence(start, end)
        val p = getCustomTextPaint(paint)
        val fm = p.fontMetricsInt
        // 此处重新计算y坐标，使字体居中
        canvas.drawText(temp.toString(), x, (y - ((y + fm.descent + y + fm.ascent) / 2 - (bottom + top) / 2)).toFloat(), p)
    }

    private fun getCustomTextPaint(srcPaint: Paint): TextPaint {
        val paint = TextPaint(srcPaint)
        // 设定字体大小, sp转换为px
        paint.textSize = fontSizePx
        return paint
    }
}